﻿using Candy.Infrastructure;
using Candy.Model;
using Candy.Web.Data;
using Candy.Web.Model;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.ObjectModel;
using System.Linq;

namespace Candy.ViewModel
{
    public class GeneEditViewModel : EntityEditViewModel<GeneDto>
    {

        private GenotypeDto _genotype;
        public GenotypeDto Genotype
        {
            get
            {
                return _genotype;

            }
            set
            {
                _genotype = value;
                Entity.Genotype = value;
                if (_genotype != null)
                    Entity.GenotypeId = _genotype.Id;
                else
                    Entity.GenotypeId = default(int?);
                RaisePropertyChanged("Genotype");
            }
        }

        private ObservableCollection<AnnotationGroupViewModel> _annotationGroups;
        public ObservableCollection<AnnotationGroupViewModel> AnnotationGroups
        {
            get
            {
                return _annotationGroups;
            }
            set
            {
                _annotationGroups = value;
                RaisePropertyChanged("AnnotationGroups");
            }
        }


        INavigationService _navigationService;
        public GeneEditViewModel(IDataService dataService, INavigationService navigationService, GeneDto gene)
            : base(dataService, gene, dataService.Genes)
        {
            _navigationService = navigationService;
            AnnotationGroups = new ObservableCollection<AnnotationGroupViewModel>();

            AnnotationGroups.Add(new AnnotationGroupViewModel(_dataService, this, AnnotationType.Description));
            AnnotationGroups.Add(new AnnotationGroupViewModel(_dataService, this, AnnotationType.MolecularFunction));
            AnnotationGroups.Add(new AnnotationGroupViewModel(_dataService, this, AnnotationType.Reference));
            //AnnotationGroups.Add(new AnnotationGroupViewModel(_dataService, this, AnnotationType.Pathway));
            //AnnotationGroups.Add(new AnnotationGroupViewModel(_dataService, this, AnnotationType.Tag));
            //AnnotationGroups.Add(new AnnotationGroupViewModel(_dataService, this, AnnotationType.Synonym));
            //AnnotationGroups.Add(new AnnotationGroupViewModel(_dataService, this, AnnotationType.History));




            if (!IsInDesignMode)
            {
                this.Canceled += GeneEditViewModel2_Canceled;
                this.Saved += GeneEditViewModel2_Saved;
                Entity.PropertyChanged += Entity_PropertyChanged;
                _genotype = Entity.Genotype;
            }
            else
            {
                LoadAnnotations.Execute(null);
            }


            // _dataService.GeneAnnotations.EntityRemoved += GeneAnnotations_EntityRemoved;
        }

        void Entity_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "AutogeneratedName" || e.PropertyName == "Genotype")
            {
                if (Entity.AutogeneratedName)
                {
                    if (this.IsEditing)
                    {
                        Entity.Name = Entity.GenotypeId.HasValue ? Autonaming.NameGene(_dataService.Genotypes.Single(x => x.Id == Entity.GenotypeId.Value).Name, Entity.Id) : Autonaming.NameGene(null, Entity.Id);
                    }
                }
                else
                {

                }
            }
        }



        private RelayCommand _loadAnnotations;
        public RelayCommand LoadAnnotations
        {
            get
            {
                return _loadAnnotations ?? (_loadAnnotations = new RelayCommand(ExecLoadAnnotations, CanLoadAnnotations));
            }
        }

        /// <summary>
        /// Checks whether the LoadAnnotations command is executable
        /// </summary>
        private bool CanLoadAnnotations()
        {
            return true;
        }



        private bool _annotationsLoaded = false;
        /// <summary>
        /// Executes the LoadAnnotations command 
        /// </summary>
        private void ExecLoadAnnotations()
        {
            if (_annotationsLoaded)
                return;
            base.ResetError();

            _dataService.LoadGeneAnnotaionAsync(Entity.Id, op =>
                {
                    if (op.HasError)
                    {
                        base.HandleDomainError(op, "Loading annotaions failed.");
                    }
                    else
                    {
                        _annotationsLoaded = true;
                        foreach (var group in AnnotationGroups)
                        {
                            var items = op.Entities.Where(x => x.Annotation == group.Type).OrderBy(x => x.ModifiedDate);
                            foreach (var item in items)
                            {
                                if (item.Annotation == AnnotationType.Reference)
                                {
                                    group.Annotations.Add(new GeneReferenceEditViewModel(_dataService, item));
                                }
                                else
                                {
                                    group.Annotations.Add(new GeneAnnotationEditViewModel(_dataService, item));
                                }
                            }
                        }
                        //var ordered = op.Entities.Select(x=>x.
                        ////op.Entities.Where(x => x.Annotation != AnnotationType.Reference && x.Annotation != AnnotationType.MolecularFunction).Select(x => new GeneAnnotationEditViewModel(_dataService, x)));
                        //foreach (var item in (op.Entities.Where(x => x.Annotation == AnnotationType.MolecularFunction).Select(x => new GeneMolFunctionEditViewModel(_dataService, x))))
                        //{
                        //    this.Annotations.Add(item);
                        //}
                        //foreach (var item in (op.Entities.Where(x => x.Annotation == AnnotationType.MolecularFunction).Select(x => new GeneMolFunctionEditViewModel(_dataService, x))))
                        //{
                        //    this.Annotations.Add(item);
                        //}
                        //foreach (var item in (op.Entities.Where(x => x.Annotation == AnnotationType.Reference).Select(x => new GeneReferenceEditViewModel(_dataService, x))))
                        //{
                        //    this.Annotations.Add(item);
                        //}
                    }
                    // _dataService.GeneAnnotations.EntityAdded += GeneAnnotations_EntityAdded;
                });
        }




        void GeneEditViewModel2_Saved(object sender, EventArgs e)
        {
            _navigationService.CloseGeneEditor();
        }

        void GeneEditViewModel2_Canceled(object sender, EventArgs e)
        {
            _navigationService.CloseGeneEditor();
        }

        protected override void OnValidateAsync(Action<bool> callback)
        {

            _dataService.GeneIdentifierExistsAsync(Entity.ProjectId, Entity.Id, Entity.GeneIdentifier, op =>
            {
                if (op.HasError)
                {
                    base.HandleDomainError(op, "Couldn't validate gene identifier.");
                    callback(false);
                }
                else
                {
                    if (op.Value)
                    {
                        //invalid we can stop now
                        //no commit if not valid
                        Entity.ValidationErrors.Add(new System.ComponentModel.DataAnnotations.ValidationResult(Web.Resources.ValidationErrorResource.GeneIdentifierAlreadyExists,
                                         new string[] { "GeneIdentifier" }));
                        callback(!op.Value);
                    }
                    else
                    {
                        if (!Entity.AutogeneratedName)
                        {
                            _dataService.GeneNameExistsAsync(Entity.ProjectId, Entity.Id, Entity.Name, op2 =>
                                {
                                    if (op2.HasError)
                                    {
                                        base.HandleDomainError(op2, "Couldn't validate gene name.");
                                        callback(false);
                                    }
                                    else
                                    {
                                        if (op2.Value)
                                        {
                                            //no commit if not valid
                                            Entity.ValidationErrors.Add(new System.ComponentModel.DataAnnotations.ValidationResult(Web.Resources.ValidationErrorResource.GeneNameAlreadyExists,
                                                             new string[] { "Name" }));
                                        }
                                        callback(!op2.Value);
                                    }
                                });

                        }
                        else
                            callback(!op.Value);
                    }

                }
            });
        }



        //private RelayCommand _addDescription;
        //public RelayCommand AddDescription
        //{
        //    get
        //    {
        //        return _addDescription ?? (_addDescription = new RelayCommand(ExecAddDescription, CanAddDescription));
        //    }
        //}

        ///// <summary>
        ///// Checks whether the AddDescription command is executable
        ///// </summary>
        //private bool CanAddDescription()
        //{
        //    return true;
        //}

        ///// <summary>
        ///// Executes the AddDescription command 
        ///// </summary>
        //private void ExecAddDescription()
        //{
        //    if (Annotations == null)
        //        Annotations = new ObservableCollection<GeneAnnotationEditViewModel>();
        //    GeneAnnotationDto dto = new GeneAnnotationDto();
        //    dto.ProjectId = _dataService.LoadedProject.Id;
        //    dto.GeneId = Entity.Id;

        //    dto.Annotation = AnnotationType.Description;
        //    dto.CreateDate = DateTime.Now;
        //    dto.ModifiedDate = DateTime.Now;
        //    _dataService.GeneAnnotations.Add(dto);
        //    //GeneAnnotationEditViewModel vm = new GeneAnnotationEditViewModel(_dataService, dto);
        //    //this.Annotations.Insert(0, vm);
        //    //vm.Edit.Execute(null);
        //}





        //private RelayCommand<GeneAnnotationEditViewModel> _deleteAnnotation;
        //public RelayCommand<GeneAnnotationEditViewModel> DeleteAnnotation
        //{
        //    get
        //    {
        //        return _deleteAnnotation ?? (_deleteAnnotation = new RelayCommand<GeneAnnotationEditViewModel>(ExecDeleteAnnotation, CanDeleteAnnotation));
        //    }
        //}

        ///// <summary>
        ///// Checks whether the DeleteAnnotation command is executable
        ///// </summary>
        //private bool CanDeleteAnnotation(GeneAnnotationEditViewModel val)
        //{
        //    return true;
        //}

        ///// <summary>
        ///// Executes the DeleteAnnotation command 
        ///// </summary>
        //private void ExecDeleteAnnotation(GeneAnnotationEditViewModel val)
        //{
        //    throw new NotImplementedException();
        //}


    }
}
